package com.wekri.wechat4j.util;

import com.alibaba.fastjson.JSONObject;
import com.wekri.wechat4j.api.material.bean.MaterialResult;
import com.wekri.wechat4j.exception.WeChatException;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.KeyStore;

/**
 * @author liuweiguo
 */
public class HttpUtils {

    private static Logger logger = LoggerFactory.getLogger(HttpUtils.class);

    private static RequestConfig requestConfig = RequestConfig.custom()
            .setSocketTimeout(1000 * 10)
            .setConnectTimeout(1000 * 10)
            .setConnectionRequestTimeout(1000 * 10)
            .build();

    private static BasicHeader[] headers = {new BasicHeader("Connection", "close"),
            new BasicHeader("Content-Type", "application/json;charset=utf-8")};

    public static <T> T get(String url, Class<T> clazz) {
        return JSONObject.parseObject(get(url), clazz);
    }

    public static <T> T postJson(String url, String jsonData, Class<T> clazz) {
        return JSONObject.parseObject(postJson(url, jsonData), clazz);
    }

    public static <T> T upload(String url, File file, Class<T> clazz) {
        return JSONObject.parseObject(upload(url, file), clazz);
    }

    /**
     * get请求
     * @param url
     * @return
     */
    public static String get(String url) {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String result = null;
        try {
            HttpGet request = new HttpGet(url);
            request.setConfig(requestConfig);
            response = httpClient.execute(request);
            result = EntityUtils.toString(response.getEntity(),"utf-8");
        } catch (IOException e) {
            logger.error("get请求异常，" + e.getMessage() + "\n get url:" + url, e);
        } finally {
            org.apache.http.client.utils.HttpClientUtils.closeQuietly(httpClient);
            org.apache.http.client.utils.HttpClientUtils.closeQuietly(response);
        }
        return result;
    }

    public static String postJson(String url, String jsonData) {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String result = null;

        HttpPost post = new HttpPost(url);
        post.setConfig(requestConfig);
        post.setHeaders(headers);

        try {
            if (StringUtils.isNotBlank(jsonData)) {
                post.setEntity(new StringEntity(jsonData, "utf-8"));
            }
            response = httpClient.execute(post);
            result = EntityUtils.toString(response.getEntity(), "utf-8");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            org.apache.http.client.utils.HttpClientUtils.closeQuietly(httpClient);
            org.apache.http.client.utils.HttpClientUtils.closeQuietly(response);
        }
        return result;
    }

    public static String upload(String url, File file) {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String result = null;

        HttpPost post = new HttpPost(url);
        post.setConfig(requestConfig);

        try {
            FileBody bin = new FileBody(file);
//            StringBody comment = new StringBody("A binary file of some kind", ContentType.TEXT_PLAIN);

            HttpEntity reqEntity = MultipartEntityBuilder.create()
                    .addPart("media", bin)
//                    .addPart("comment", comment)
                    .build();

            post.setEntity(reqEntity);
            response = httpClient.execute(post);
            result = EntityUtils.toString(response.getEntity(), "utf-8");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            org.apache.http.client.utils.HttpClientUtils.closeQuietly(httpClient);
            org.apache.http.client.utils.HttpClientUtils.closeQuietly(response);
        }
        return result;
    }

    public static byte[] getFile(String url) throws Exception {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        byte[] buffer = null;
        try {
            HttpGet request = new HttpGet(url);
            RequestConfig config = RequestConfig
                    .custom()
                    .setSocketTimeout(120000)
                    .setConnectTimeout(120000)
                    .build();
            request.setConfig(config);
            response = httpClient.execute(request);
            buffer = EntityUtils.toByteArray(response.getEntity());
        } catch (IOException e) {
            logger.error("请求[" + url + "]异常", e);
        } finally {
            org.apache.http.client.utils.HttpClientUtils.closeQuietly(httpClient);
            org.apache.http.client.utils.HttpClientUtils.closeQuietly(response);
        }
        //先读取，判断大小，是否超过1k，小于1k为json错误
        //失败{"errcode":40001,"errmsg":"invalid credential, access_token is invalid or not latest hint: [Q79jka0783vr32!]"}
        if (null != buffer && buffer.length < 500) {
            String respStr = new String(buffer, Charset.forName("UTF-8"));
            logger.error("从微信端下载图片失败：{}", respStr);
            throw new WeChatException(respStr);
        }
        return buffer;
    }

    public static String postXmlWithCert(String url, String xmlData, Cert cert) {
        CloseableHttpClient httpclient = null;
        CloseableHttpResponse response = null;
        try {
            // 证书
            KeyStore ks = KeyStore.getInstance("PKCS12");
            ks.load(cert.getCertInputStream(), cert.getPassword().toCharArray());

            // Trust own CA and all self-signed certs
            SSLContext sslContext = SSLContexts.custom().loadKeyMaterial(ks, cert.getPassword().toCharArray()).build();

            // Allow TLSv1 protocol only
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                    sslContext,
                    new String[]{"TLSv1"},
                    null,
                    SSLConnectionSocketFactory.getDefaultHostnameVerifier());
            httpclient = HttpClients.custom()
                    .setSSLSocketFactory(sslsf)
                    .build();

            HttpPost post = new HttpPost(url);
            if (StringUtils.isNotBlank(xmlData)) {
                post.setEntity(new StringEntity(xmlData, "utf-8"));
            }

            logger.info("Executing request :{}", post.getRequestLine());

            response = httpclient.execute(post);
            HttpEntity entity = response.getEntity();

            return EntityUtils.toString(entity);
        } catch (Exception e) {
            logger.error("", e);
        } finally {
            org.apache.http.client.utils.HttpClientUtils.closeQuietly(httpclient);
            org.apache.http.client.utils.HttpClientUtils.closeQuietly(response);
        }
        return null;
    }

    public static MaterialResult getMaterial(String url, String jsonParam) {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        MaterialResult result = null;
        byte[] buffer = null;

        HttpPost post = new HttpPost(url);
        post.setConfig(requestConfig);
        post.setHeaders(headers);

        try {
            if (StringUtils.isNotBlank(jsonParam)) {
                post.setEntity(new StringEntity(jsonParam, "utf-8"));
            }
            response = httpClient.execute(post);
            if (response.containsHeader("Content-Type")
                    && "text/plain".equals(response.getFirstHeader("Content-Type").getValue())) {
//                Content-Length: 68
                result = JSONObject.parseObject(EntityUtils.toString(response.getEntity(), "utf-8"), MaterialResult.class);
                result.setResponseType(response.getFirstHeader("Content-Type").getValue());
            } else {
                result = new MaterialResult();
                result.setBytes(EntityUtils.toByteArray(response.getEntity()));
                result.setResponseType(response.getFirstHeader("Content-disposition").getValue());
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            org.apache.http.client.utils.HttpClientUtils.closeQuietly(httpClient);
            org.apache.http.client.utils.HttpClientUtils.closeQuietly(response);
        }
        //先读取，判断大小，是否超过1k，小于1k为json错误
        //失败{"errcode":40001,"errmsg":"invalid credential, access_token is invalid or not latest hint: [Q79jka0783vr32!]"}
        if (null != buffer && buffer.length < 500) {
            String respStr = new String(buffer, Charset.forName("UTF-8"));
            logger.error("从微信端下载素材失败：{}", respStr);
            throw new WeChatException(respStr);
        }
        return result;
    }
}
